package momo.multitree.simulation;

import momo.multitree.algo.AllTreeVisitor;
import momo.multitree.structure.*;
import momo.multitree.util.EdgeQuickSort;

public class GlobalOptTree implements AllTreeVisitor
{
	private Tree bestLatTree, bestCostTree, bestStabTree;
	private double bestLat, bestCost, bestStab;
	private double worstLat, worstCost, worstStab;
	private double minDist = Double.POSITIVE_INFINITY;
	
	private Tree bestTree;
	
	public GlobalOptTree(Tree bestLatTree, Tree bestCostTree, Tree bestStabTree)
	{
		this.bestLatTree = bestLatTree;
		this.bestCostTree = bestCostTree;
		this.bestStabTree = bestStabTree;
		
		setup();
	}
	
	public void setup()
	{
		bestLat = bestLatTree.compWeightedLatency();
		worstLat = bestCostTree.compWeightedLatency() > bestStabTree.compWeightedLatency() ? bestCostTree.compWeightedLatency() :  bestStabTree.compWeightedLatency();
		
		bestCost = bestCostTree.compCost(false);
		worstCost = bestLatTree.compCost(false) > bestStabTree.compCost(false) ? bestLatTree.compCost(false) : bestStabTree.compCost(false);  
		
		bestStab = bestStabTree.compStability();
		worstStab = bestLatTree.compStability() > bestCostTree.compStability() ? bestLatTree.compStability() : bestCostTree.compStability();
		
//		System.out.println("bestLat: " + bestLat);
//		System.out.println("worstLat: " + worstLat);
		
//		System.out.println("bestCost: " + bestCost);
//		System.out.println("worstCost: " + worstCost);
		
//		System.out.println("bestStab: " + bestStab);
//		System.out.println("worstStab: " + worstStab);
//		System.out.println("\n\n");
		
		visit(bestLatTree);
		visit(bestCostTree);
		visit(bestStabTree);
	}
	
	public double dist(Tree t)
	{
		double latT, costT, stabT;
		double lat = t.compWeightedLatency();
		double cost = t.compCost(false);
		double stab = t.compStability();
		
//		System.out.println("lat: " + lat);
//		System.out.println("cost: " + cost);
//		System.out.println("stab: " + stab);
		
		// Stab'(T) = ( ( Stab(T) - Stab* ) / ( Stab^N - Stab* ) )
		latT = ( lat - bestLat ) / ( worstLat - bestLat );
		if ( Double.isNaN(latT) || Double.isInfinite(latT) ) latT = 0;
		
		costT = ( cost - bestCost ) / ( worstCost - bestCost );
		if ( Double.isNaN(costT) || Double.isInfinite(costT) ) costT = 0;
		
		stabT = ( stab - bestStab ) / ( worstStab - bestStab );
		if ( Double.isNaN(stabT) || Double.isInfinite(stabT) ) stabT = 0;
		
//		System.out.println("latT: " + latT);
//		System.out.println("costT: " + costT);
//		System.out.println("stabT: " + stabT);
		
		// dist( (C*, L*, Stab*), (C'(T), L'(T), Stab'(T))  )
		// dist( (X1,X2,X3), (Y1,Y2,Y3) ) = sqrt ( (X1-Y1)^2 + (X2 - Y2)^2 + (X3 - Y3)^2)

		double dist = Math.sqrt( Math.pow(latT, 2) + Math.pow(costT, 2) + Math.pow(stabT, 2) );
		return dist;
	}

	public void visit(Tree t)
	{
		double curTreeDist = dist(t);
//		System.out.println("curTreeDist: " + curTreeDist);
//		System.out.println("minDist: " + minDist+"\n");
		if ( curTreeDist < minDist )
		{
			minDist = curTreeDist;
			bestTree = t;
		}
	}
	
	public Tree getBestTree()
	{
		return bestTree;
	}
	
	public String toString()
	{
		return bestLatTree.compWeightedLatency() + ", " +
				bestLatTree.compCost(false) + ", " +
				bestLatTree.compStability() + ", " +
				bestCostTree.compWeightedLatency() + ", " +
				bestCostTree.compCost(false) + ", " +
				bestCostTree.compStability() + ", " +
				bestStabTree.compWeightedLatency() + ", " +
				bestStabTree.compCost(false) + ", " +
				bestStabTree.compStability() + ", " +
				bestTree.compWeightedLatency() + ", " +
				bestTree.compCost(false) + ", " +
				bestTree.compStability();
	}

}
